package com.ruoyi.web.common.util;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.iot.domain.IotDataWeather;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

public class WeatherUtil {

    //登录
    private static final String API_URL_PRE = "https://np7fbykn4v.re.qweatherapi.com";

    private static final String API_WEATHER_NOW = "/v7/weather/now";

    // /v7/weather/{hours} hours=168h 168小时预报。
    private static final String API_FORECAST_WEATHER = "/v7/weather/";


    private static final String API_MINUTELY = "/v7/minutely/5m";

    private static final String API_KEY = "991abf7c18164cabba54851dc03265d5";

    private static final String LOCATION = "112.96,30.89";

    private static final String LOCATION_ID = "101201403";

    public static String getToken() throws InvalidKeySpecException, InvalidKeyException, NoSuchAlgorithmException, SignatureException {
        // Private key
        String privateKeyString = API_KEY;
        privateKeyString = privateKeyString.trim().replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").trim();
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec encoded = new PKCS8EncodedKeySpec(privateKeyBytes);
        PrivateKey privateKey = new EdDSAPrivateKey(encoded);

        // Header
        String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"YOUR_KEY_ID\"}";

        // Payload
        long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
        long exp = iat + 900;
        String payloadJson = "{\"sub\": \"YOUR_PROJECT_ID\", \"iat\": " + iat + ", \"exp\": " + exp + "}";

        // Base64url header+payload
        String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
        String data = headerEncoded + "." + payloadEncoded;

        EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);

        // Sign
        final Signature s = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
        s.initSign(privateKey);
        s.update(data.getBytes(StandardCharsets.UTF_8));
        byte[] signature = s.sign();

        String signatureString = Base64.getUrlEncoder().encodeToString(signature);

        System.out.println("Signature: \n" + signatureString);

// Print Token
        return data + "." + signatureString;
    }
    public static JSONObject getWeatherNow(String location) throws InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {

        HttpRequest request = HttpUtil.createGet(API_URL_PRE + API_WEATHER_NOW);
        Map<String, Object> params = new HashMap<>();
        params.put("location", location);
//        request.header("Authorization", "Bearer " + getToken());
        request.header("X-QW-Api-Key", API_KEY);
        request.form(params);

        // 发送请求并获取响应
        String response = request.execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(response);
        return jsonObject;
    }
    //逐小时天气预报API
    public static JSONObject getForecastWeather(String location, String hours) {
        HttpRequest request = HttpUtil.createGet(API_URL_PRE + API_FORECAST_WEATHER + hours  );
        Map<String, Object> params = new HashMap<>();
        params.put("location", location);
//        request.header("Authorization", "Bearer " + getToken());
        request.header("X-QW-Api-Key", API_KEY);
        request.form(params);

        // 发送请求并获取响应
        String response = request.execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(response);
        return jsonObject;
    }
    //获取未来2小时每5分钟降雨预报数据
    public static JSONObject getMinutely(String location) {
        HttpRequest request = HttpUtil.createGet(API_URL_PRE + API_MINUTELY );
        Map<String, Object> params = new HashMap<>();
        params.put("location", location);
//        request.header("Authorization", "Bearer " + getToken());
        request.header("X-QW-Api-Key", API_KEY);
        request.form(params);

        // 发送请求并获取响应
        String response = request.execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(response);
        return jsonObject;
    }
    public static IotDataWeather convertUnits() throws InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        IotDataWeather weather = new IotDataWeather();

        String hours = "168h";
        JSONObject nowWeatherJSON = getWeatherNow(LOCATION);

        JSONObject nowWeatherData = (JSONObject) nowWeatherJSON.getOrDefault("now",null);

        JSONObject forecastWeatherJSON = getForecastWeather(LOCATION, hours);

        List<JSONObject> forecastWeatherData = (List<JSONObject>) forecastWeatherJSON.getOrDefault("hourly",new ArrayList<JSONObject>());

        JSONObject minutelyJSON = getMinutely(LOCATION);

        List<JSONObject> minutelyData = (List<JSONObject>) minutelyJSON.getOrDefault("minutely",new ArrayList<JSONObject>());

        weather.setTemp(nowWeatherData.getStr("temp"));
        weather.setFeelsLike(nowWeatherData.getStr("feelsLike"));
        weather.setHumidity(nowWeatherData.getStr("humidity"));
        weather.setPrecip(nowWeatherData.getStr("precip"));
        weather.setPressure(nowWeatherData.getStr("pressure"));
        weather.setWindScale(nowWeatherData.getStr("windScale"));
        weather.setWindDir(nowWeatherData.getStr("windDir"));
        weather.setVis(nowWeatherData.getStr("vis"));
        weather.setDew(nowWeatherData.getStr("dew"));
        weather.setCloud(nowWeatherData.getStr("cloud"));

        weather.setFxTimeForecast(forecastWeatherData.stream().map(item -> item.getStr("fxTime")).collect(Collectors.toList()).toString());
        weather.setTempForecast(forecastWeatherData.stream().map(item -> item.getStr("temp")).collect(Collectors.toList()).toString());
        weather.setWindDirForecast(forecastWeatherData.stream().map(item -> item.getStr("windDir")).collect(Collectors.toList()).toString());
        weather.setWindScaleForecast(forecastWeatherData.stream().map(item -> item.getStr("windScale")).collect(Collectors.toList()).toString());
        weather.setWindSpeedForecast(forecastWeatherData.stream().map(item -> item.getStr("windSpeed")).collect(Collectors.toList()).toString());
        weather.setHumidityForecast(forecastWeatherData.stream().map(item -> item.getStr("humidity")).collect(Collectors.toList()).toString());
        weather.setPopForecast(forecastWeatherData.stream().map(item -> item.getStr("pop")).collect(Collectors.toList()).toString());
        weather.setPrecipForecast(forecastWeatherData.stream().map(item -> item.getStr("precip")).collect(Collectors.toList()).toString());
        weather.setPressureForecast(forecastWeatherData.stream().map(item -> item.getStr("pressure")).collect(Collectors.toList()).toString());
        weather.setCloudForecast(forecastWeatherData.stream().map(item -> item.getStr("cloud")).collect(Collectors.toList()).toString());
        weather.setDewForecast(forecastWeatherData.stream().map(item -> item.getStr("dew")).collect(Collectors.toList()).toString());

        weather.setFxTimeMinutely(minutelyData.stream().map(item -> item.getStr("fxTime")).collect(Collectors.toList()).toString());
        weather.setPrecipMinutely(minutelyData.stream().map(item -> item.getStr("precip")).collect(Collectors.toList()).toString());
        weather.setTypeMinutely(minutelyData.stream().map(item -> item.getStr("type")).collect(Collectors.toList()).toString());
        weather.setReportTime(new Date());
        return weather;
    }
}
